package top.jolyoulu.codegenweb.service.bll.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.jolyoulu.codegenweb.config.SecurityConfig;
import top.jolyoulu.codegenweb.entity.bo.form.DataSourceInfoFormBO;
import top.jolyoulu.codegenweb.entity.po.DataSourceInfo;
import top.jolyoulu.codegenweb.service.bll.ApiMysqlDataSourceService;
import top.jolyoulu.codegenweb.service.dal.DataSourceInfoService;
import top.jolyoulu.corecommon.utils.encryption.DESUtils;
import top.jolyoulu.modules.druidmodule.constant.DBConstant;
import top.jolyoulu.modules.druidmodule.entity.TableInfo;
import top.jolyoulu.modules.druidmodule.utils.datasource.DruidUtils;
import top.jolyoulu.modules.druidmodule.utils.db.mysql.MysqlDBUtils;
import top.jolyoulu.webcommon.enums.GlobalExpType;
import top.jolyoulu.webcommon.excption.GlobalException;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: JolyouLu
 * @Date: 2023/4/5 16:36
 * @Description
 */
@Slf4j
@Service
public class ApiMysqlDataSourceServiceImpl implements ApiMysqlDataSourceService {

    @Autowired
    private DataSourceInfoService dataSourceInfoService;

    @Autowired
    private SecurityConfig securityConfig;

    @PostConstruct
    public void init() {
        //加载所有数据源

        List<DataSourceInfo> list = dataSourceInfoService.list(new LambdaQueryWrapper<DataSourceInfo>()
                .eq(DataSourceInfo::getDatabaseType, 1));
        list.stream()
                .filter(f1 -> StringUtils.isNotBlank(f1.getHost())
                        && StringUtils.isNotBlank(f1.getUsername())
                        && StringUtils.isNotBlank(f1.getPort())
                        && StringUtils.isNotBlank(f1.getPassword()))
                .filter(f2 -> {
                    try {
                        return this.testConnection(new DataSourceInfoFormBO()
                                .setHost(f2.getHost())
                                .setPort(f2.getPort())
                                .setUsername(f2.getUsername())
                                .setPassword(DESUtils.decrypt(f2.getPassword(), securityConfig.getPwdSecretKey())));
                    } catch (Exception e) {
                        return false;
                    }
                })
                .forEach(item -> {
                    log.info("{}:{}/{} 初始化成功",item.getHost(),item.getPort(),item.getSchemaName());
                    this.testConnectionById(item.getId());
                });

    }

    @Override
    public boolean testConnection(DataSourceInfoFormBO bo) {
        MysqlDBUtils dbUtils = MysqlDBUtils.build(bo.getHost(), bo.getPort(), bo.getUsername(), bo.getPassword());
        return dbUtils.check();
    }

    @Override
    public boolean testConnectionById(String id) {
        boolean test = false;
        try {
            DataSourceInfo info = dataSourceInfoService.getById(id);
            if (Objects.isNull(info)) {
                throw new GlobalException(GlobalExpType.PARAM_ERROR);
            }
            Properties properties = new Properties();
            properties.setProperty("driverClassName", "com.mysql.cj.jdbc.Driver");
            properties.setProperty("url", DBConstant.getMysqlUrl(info.getHost(), info.getPort()));
            properties.setProperty("username", info.getUsername());
            //密码解密
            String pwd = DESUtils.decrypt(info.getPassword(), securityConfig.getPwdSecretKey());
            properties.setProperty("password", pwd);
            DataSource dataSource = DruidUtils.creatDataSource(id, properties);
            MysqlDBUtils dbUtils = MysqlDBUtils.build(dataSource.getConnection());
            test = dbUtils.check();
            dbUtils.close();
            if (!test) {
                throw new GlobalException(GlobalExpType.UNAUTH_ERROR);
            }
        } catch (SQLException e) {
            log.error("", e);
        }
        return test;
    }

    @Override
    public List<String> schemas(String id) {
        List<String> res = new ArrayList<>();
        try {
            DataSourceInfo info = dataSourceInfoService.getById(id);
            if (Objects.isNull(info)) {
                throw new GlobalException(GlobalExpType.PARAM_ERROR);
            }
            DataSource dataSource = DruidUtils.getDataSource(id);
            MysqlDBUtils dbUtils = MysqlDBUtils.build(dataSource.getConnection());
            res = dbUtils.selectDatabases();
            dbUtils.close();
        } catch (SQLException e) {
            log.error("", e);
        }
        return res;
    }

    @Override
    public List<String> tables(String id) {
        ArrayList<String> res = new ArrayList<>();
        try {
            DataSourceInfo info = dataSourceInfoService.getById(id);
            if (Objects.isNull(info)) {
                throw new GlobalException(GlobalExpType.PARAM_ERROR);
            }
            if (StringUtils.isBlank(info.getSchemaName())) {
                throw new GlobalException(GlobalExpType.SCHEMA_NON_EXIST);
            }
            DataSource dataSource = DruidUtils.getDataSource(id);
            if (Objects.isNull(dataSource)){
                throw new GlobalException(GlobalExpType.SCHEMA_NON_EXIST);
            }
            MysqlDBUtils dbUtils = MysqlDBUtils.build(dataSource.getConnection());
            List<TableInfo> tableInfos = dbUtils.selectTables(info.getSchemaName());
            res.addAll(tableInfos.stream().map(TableInfo::getTableName).collect(Collectors.toList()));
        } catch (SQLException e) {
            log.error("", e);
        }
        return res;
    }

}
